/***
 * Copyright (c) 2020 murenchao Flowing is licensed under Mulan PSL v2. You can use this software according to the terms
 * and conditions of the Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at: http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
 * BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. See the Mulan PSL v2 for more
 * details.
 */
package cool.taomu.web.core;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentSkipListMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;

import cool.taomu.web.controller.WebSocketConteroller;
import cool.taomu.web.entity.Message;
import jakarta.websocket.OnClose;
import jakarta.websocket.OnMessage;
import jakarta.websocket.OnOpen;
import jakarta.websocket.Session;
import jakarta.websocket.server.ServerEndpoint;

/**
 * The Class WebSocketServer.
 */
@ServerEndpoint("/socket")
public class WebSocketServer {
    private final static Logger LOG = LoggerFactory.getLogger(WebSocketServer.class);

    private static class Mapping {
        public Class<?> zlass;
        public String method;
    }

    private final static ConcurrentSkipListMap<String, Mapping> MAPPING;
    private Session session;

    static {
        MAPPING = new ConcurrentSkipListMap<>();
        scann(WebSocketConteroller.class);
    }

    private static void scann(Class<?> zlass) {
        for (Method method : zlass.getMethods()) {
            Type type = method.getAnnotation(Type.class);
            if (type != null) {
                Mapping map = new Mapping();
                map.zlass = zlass;
                map.method = method.getName();
                MAPPING.put(type.value(), map);
            }
        }
    }

    @OnOpen
    public void onOpen(Session session) {
        System.out.println("session opened = " + session.getId());
        this.session = session;
    }

    @OnMessage
    public void onMessage(String message) {
        System.out.println("message = " + message);
        Message msg = new Gson().fromJson(message, Message.class);
        try {
            if (MAPPING.containsKey(msg.getType())) {
                Mapping map = MAPPING.get(msg.getType());
                Object obj = map.zlass.newInstance();
                broadcast(map.zlass.getMethod(map.method, String.class).invoke(obj, msg.getData()));
            }
        } catch (Exception ex) {
            LOG.info(ex.getMessage(), ex.fillInStackTrace());
        }
    }

    @OnClose
    public void onClose(Session session) {
        System.out.println("session close = " + session.getId());
        try {
            this.session.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        // clientSessions.remove(session.getId());
    }

    void broadcast(Object message) {
        this.session.getAsyncRemote().sendText(String.valueOf(message));
        /* for (Session session : clientSessions.values()) {
            session.getAsyncRemote().sendText(message);
        }*/
    }
}